﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Minio;
using Minio.DataModel.Args;
using Minio.Exceptions;

namespace HSGD.Services {
    public class FileInfotmation {
        /// <summary>
        /// id
        /// </summary>
        public string Id { get; set; }

        /// <summary>
        /// 文件名称（真实的文件名）
        /// </summary>
        public string FileName1 { get; set; }

        /// <summary>
        /// 文件类型
        /// </summary>
        public string FileType { get; set; }


        /// <summary>
        /// 文件后缀
        /// </summary>
        public string FileExtension { get; set; }
        /// <summary>
        /// 给前端展示的文件名（上传相同文件的情况下）
        /// </summary>
        public string FileName2 { get; set; }
    }

    /// <summary>
    /// 文件类型枚举类
    /// </summary>
    public enum FileType {
        /// <summary>
        /// 视频文件
        /// </summary>
        video,
        /// <summary>
        /// 文档文件
        /// </summary>
        document,
        /// <summary>
        /// 图片文件
        /// </summary>
        image,

        /// <summary>
        /// // Python源文件
        /// </summary>
        PythonSourceFile,
        /// <summary>
        /// // MALTAB脚本文件
        /// </summary>
        MATLABScriptFile,
        /// <summary>
        ///  // dll文件  
        /// </summary>
        DLLFile,


        /// <summary>
        /// 其他类型文件
        /// </summary>
        other
    }

    public class MinioFileService {
        private readonly IMinioClient minioClient;
        //private readonly MongoService mongoService;
        private readonly ILogger<MinioFileService> logger;
        const string bucketName = "hsgd-ems1";


        public MinioFileService(IMinioClient minioClient, ILogger<MinioFileService> logger) {
            this.minioClient = minioClient;
            this.logger = logger;
        }


        public async Task<string> Upload(IFormFile file) {
            try {
                logger.LogInformation("文件开始上传");
                //string uploadsPath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "uploads");
                //if (!Directory.Exists(uploadsPath)) {
                //    Directory.CreateDirectory(uploadsPath);
                //}
                //string fileName = file.FileName;
                //string filePath = Path.Combine(uploadsPath, fileName);
                //string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
                //string fileExtension = Path.GetExtension(fileName);
                //string newFileName = null;
                //int counter = 1;
                //while (File.Exists(filePath)) {
                //    //重新命名文件
                //    string Name = $"{fileNameWithoutExtension}_{counter}{fileExtension}";
                //    filePath = Path.Combine(uploadsPath, Name);
                //    newFileName = Path.GetFileNameWithoutExtension(filePath);
                //    counter++;
                //}
                //if (newFileName == null) {
                //    newFileName = Path.GetFileNameWithoutExtension(fileName);
                //}
                //using (var stream = new FileStream(filePath, FileMode.Create)) {
                //    file.CopyTo(stream);
                //}

                //AddFileInfo(filePath, Path.GetFileNameWithoutExtension(fileName), newFileName);
                var beArgs = new BucketExistsArgs().WithBucket(bucketName);
                bool found = await minioClient.BucketExistsAsync(beArgs).ConfigureAwait(false);
                if (!found) {
                    var mbArgs = new MakeBucketArgs().WithBucket(bucketName);
                    await minioClient.MakeBucketAsync(mbArgs).ConfigureAwait(false);
                }
                string fileName = $"{Guid.NewGuid():N}{Path.GetExtension(file.FileName)}";
                string objectName = $"/{DateTime.Now:yyyy/MM/dd}/{fileName}";
                using Stream stream = file.OpenReadStream();
                // 设置上传文件的对象名
                //var objectName =  Guid.NewGuid().ToString() + file.ex;
                //var objectName = $"{Guid.NewGuid():N}{file.FileName[file.FileName.LastIndexOf('.')..]}";
                var putObjectArgs = new PutObjectArgs()
                   .WithBucket(bucketName)
                   .WithObject(objectName)
                   //.WithFileName(filePath)
                   .WithStreamData(stream)
                    .WithObjectSize(file.Length)
                   .WithContentType(file.ContentType);
                await minioClient.PutObjectAsync(putObjectArgs).ConfigureAwait(false);
                return objectName;
            }
            catch (MinioException ex) {
                throw new Exception(ex.ServerMessage);
            }
        }

        /// <summary>
        /// 获取桶列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<string>> GetBuckets() {
            var list = await minioClient.ListBucketsAsync().ConfigureAwait(false);
            var buckets = list.Buckets.Select(b => b.Name).ToList();
            return buckets;
        }



        /// <summary>
        /// 文件信息入库
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="name1">前端展示文件名</param>
        /// <param name="name2">真实的文件名</param>
        /// <returns></returns>
        public FileInfotmation AddFileInfo(string filePath, string name1, string name2) {
            FileInfotmation fileInformation = new FileInfotmation() {
                Id = $"{Guid.NewGuid():N}",
                FileExtension = Path.GetExtension(filePath),
                FileName1 = name2,
                FileType = DetermineFileType(Path.GetExtension(filePath)),
                FileName2 = name1
            };
            //mongoService.GetFileInformationCollection().InsertOne(fileInformation);
            return fileInformation;
        }




        /// <summary>
        /// 下载接口
        /// </summary>
        /// <returns></returns>
        public async Task<Tuple<MemoryStream, string>> DownloadAsync(string name) {
            try {
                var statObjectArgs = new StatObjectArgs()
                   .WithBucket(bucketName)
                   .WithObject(name);
                await minioClient.StatObjectAsync(statObjectArgs);

                var memoryStream = new MemoryStream();
                var getObjectArgs = new GetObjectArgs()
                    .WithBucket(bucketName)
                    .WithObject(name)
                    .WithCallbackStream(stream => stream.CopyTo(memoryStream));
                var res = await minioClient.GetObjectAsync(getObjectArgs).ConfigureAwait(false);
                memoryStream.Position = 0;
                return Tuple.Create(memoryStream, res.ContentType);
            }
            catch (MinioException ex) {
                throw new Exception(ex.ServerMessage);
            }
        }

        /// <summary>
        /// 后缀名枚举
        /// </summary>
        /// <param name="fileExtension"></param>
        /// <returns></returns>
        public string DetermineFileType(string fileExtension) {
            HashSet<string> supportedImageExtensions = new HashSet<string>
            {
             ".jpg",".jpeg", ".png",".gif",".bmp",".tiff",".tif",".svg",".webp", ".ico"
         };

            HashSet<string> supportedVideoExtensions = new HashSet<string>
            {
             ".mp4",".avi",".mkv",".mov",".wmv",".flv",".webm"
         };

            HashSet<string> supportedDocumentExtensions = new HashSet<string>
            {
             ".doc",".docx",".pdf",".txt",".ppt",".pptx",".xls",".xlsx",
         };
            if (supportedDocumentExtensions.Contains(fileExtension.ToLower())) {
                return FileType.document.ToString();
            }
            else if (supportedImageExtensions.Contains(fileExtension.ToLower())) {
                return FileType.image.ToString();
            }
            else if (supportedVideoExtensions.Contains(fileExtension.ToLower())) {
                return FileType.video.ToString();
            }
            else {
                return FileType.other.ToString();
            }
        }
    }
}
